import { BizError, ErrorCode, transError } from '@/service/error';
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import type { z } from 'zod';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

export function result(result?: null): { result: null; error: null };
export function result<T>(result: T): { result: T; error: null };
export function result(
  error: unknown,
  message: string,
): { result: null; error: ReturnType<typeof transError> };
export function result(resultOrError: unknown, message?: string) {
  if (typeof message === 'string') {
    console.error(resultOrError);
    return { result: null, error: transError(resultOrError, message) };
  }
  if (resultOrError === null || resultOrError === undefined)
    return { result: null, error: null };
  return { result: resultOrError, error: null };
}

export const checkEnv = (name: string, defaultVal?: string) => {
  const val = process.env[name] ?? defaultVal;
  if (!val) {
    console.error(`env ${name} not existed`);
    process.exit(1);
  }
  return val;
};

export const withZod = <
  T extends z.ZodTypeAny,
  F extends (args: z.infer<T>) => any,
>(
  schema: T,
  func: F,
) => {
  return (
    args: z.infer<T>,
  ):
    | ReturnType<F>
    | Promise<{ error: ReturnType<typeof transError>; result: null }> => {
    const parsedArgs = schema.safeParse(args);
    if (!parsedArgs.success) {
      const message = parsedArgs.error.issues[0].message;
      return Promise.resolve().then(() =>
        result(new BizError(ErrorCode.InvalidParams, message), message),
      );
    }
    return func(parsedArgs.data);
  };
};

export const calculateBoundingBox = (
  latitude: number,
  longitude: number,
  radiusInMeters: number,
) => {
  const earthRadius = 6371000; // 地球半径，单位为米

  // 计算经度的变化
  const deltaLongitude =
    radiusInMeters / earthRadius / Math.cos((latitude * Math.PI) / 180);

  // 计算纬度的变化
  const deltaLatitude = radiusInMeters / earthRadius;

  // 左上角坐标
  const topLeftLatitude = latitude + (deltaLatitude * 180) / Math.PI;
  const topLeftLongitude = longitude - (deltaLongitude * 180) / Math.PI;

  // 右下角坐标
  const bottomRightLatitude = latitude - (deltaLatitude * 180) / Math.PI;
  const bottomRightLongitude = longitude + (deltaLongitude * 180) / Math.PI;

  return {
    topLeft: { latitude: topLeftLatitude, longitude: topLeftLongitude },
    bottomRight: {
      latitude: bottomRightLatitude,
      longitude: bottomRightLongitude,
    },
  };
};
